package com.xxxx.spring.day11;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

public class D11 {
    public static void main(String[] args) {
        /**
         *  两个切面概念
         *  aspect =
         *          通知1(advice) + 切点1(pointcut)
         *          通知2(advice) + 切点2(pointcut)
         *          通知3(advice) + 切点3(pointcut)
         *   ...
         *   advisor = 更细粒度的切面,包含一个通知和切点
         */

        // 1.备好切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        // 2.备好通知
        MethodInterceptor advice = invocation -> {
            System.out.println("before...");
            Object result = invocation.proceed(); // 调用目标
            System.out.println("after...");
            return result;
        };
        // 3.备好切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

        /**
         *  4.创建代理
         *      a. proxyTargetClass = false , 目标实现了接口,用 jdk 实现
         *      b. proxyTargetClass = false , 目标没有实现接口,用 cglib 实现
         *      c. proxyTargetClass = true , 总是使用 cglib 实现
         */
        Target1 target = new Target1();
        ProxyFactory factory =  new ProxyFactory();
        factory.setTarget(target);
        factory.addAdvisor(advisor);
        // 告诉 ProxyFactory 目标实现了接口
        factory.setInterfaces(target.getClass().getInterfaces());
        // proxyTargetClass = true , 总是使用 cglib 实现
        factory.setProxyTargetClass(true);
        I1 proxy = (I1)factory.getProxy();
        System.out.println(proxy.getClass());  // 如果不告诉 ProxyFactory 实现接口 则默认 cglib
        proxy.foo();
        proxy.bar();

    }

    interface I1{
        void foo();

        void bar();
    }

    static class Target1 implements I1{
        @Override
        public void foo() {
            System.out.println("target1 foo");
        }

        @Override
        public void bar() {
            System.out.println("target1 bar");
        }
    }

    static class Target2 implements I1{
        @Override
        public void foo() {
            System.out.println("target2 foo");
        }

        @Override
        public void bar() {
            System.out.println("target2 bar");
        }
    }
}
